home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume25 / pclcomp / part01 next >
Encoding:
Text File  |  1991-11-03  |  55.3 KB  |  2,342 lines

  1. Newsgroups: comp.sources.misc
  2. From: tony@sdd.hp.com (Tony Parkhurst)
  3. Subject:  v25i010:  pclcomp - HP-PCL Compression Filter, Part01/02
  4. Message-ID: <csm-v25i010=pclcomp.173706@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 2d1030bb05a81a220a089fb190e69865
  6. Date: Sun, 3 Nov 1991 23:37:34 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tony@sdd.hp.com (Tony Parkhurst)
  10. Posting-number: Volume 25, Issue 10
  11. Archive-name: pclcomp/part01
  12. Environment: LaserJet
  13. Supersedes: pclcomp: Volume 19, Issue 13-14
  14.  
  15. Here is the latest version of pclcomp.  Improvements are basically related
  16. to bug fixes, supporting obsolete (but highly used) escape sequences, and
  17. a new and improved Mode 2 compression routine.
  18.  
  19. -- Tony Parkhurst    (tony@sdd.hp.com)
  20.  
  21. #!/bin/sh
  22. # This is a shell archive (produced by shar 3.49)
  23. # To extract the files from this archive, save it to a file, remove
  24. # everything above the "!/bin/sh" line above, and type "sh file_name".
  25. #
  26. # existing files will NOT be overwritten unless -c is specified
  27. #
  28. # This is part 1 of a multipart archive                                    
  29. # do not concatenate these parts, unpack them in order with /bin/sh        
  30. #
  31. # This shar contains:
  32. # length  mode       name
  33. # ------ ---------- ------------------------------------------
  34. #   1508 -rw-rw-r-- README
  35. #   1431 -r--r--r-- getopt.c
  36. #   3851 -r--r--r-- pclcomp.1
  37. #  64599 -r--r--r-- pclcomp.c
  38. #   4059 -rw-rw-r-- pclcomp.man
  39. #    415 -rw-rw-r-- printer.note
  40. #
  41. if test -r _shar_seq_.tmp; then
  42.     echo 'Must unpack archives in sequence!'
  43.     echo Please unpack part `cat _shar_seq_.tmp` next
  44.     exit 1
  45. fi
  46. # ============= README ==============
  47. if test -f 'README' -a X"$1" != X"-c"; then
  48.     echo 'x - skipping README (File already exists)'
  49.     rm -f _shar_wnt_.tmp
  50. else
  51. > _shar_wnt_.tmp
  52. echo 'x - extracting README (Text)'
  53. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  54. X
  55. X
  56. X     This is pclcomp -- An HP-PCL compression filter.  It reads in
  57. PCL graphics files, and outputs compressed PCL files which may be sent
  58. directly to printers that support the compressions.  A partial list of
  59. printer support is included.
  60. X
  61. X     Why use pclcomp?
  62. X
  63. X    1)  PCL files are much smaller ( up to 90% ).
  64. X
  65. X    2)  Graphics printing on a LaserJet (IIP or III) is faster.
  66. X
  67. X
  68. X     If you have a LaserJet II that does not support compression, you can
  69. still compress the files for storage, and decompress them while printing.
  70. X
  71. X     I wrote this program for testing.  This is NOT an HP product.  It will
  72. NOT be supported by HP, but rather myself, in my spare time, if need be.
  73. X
  74. X     If you need real support for driver development, then call Hewlett-
  75. Packard directly, preferably the ISV support group at the Boise Division.
  76. X
  77. X     You may use parts of this code within your drivers to support compression
  78. if you wish.
  79. X
  80. X     I did what I think is a reasonable job to make the program work for
  81. most possible PCL files.  Please feel free to send comments, complaints 
  82. or suggestions to me at tony@sdd.hp.com.  If you have a file that does
  83. not survive the filter intact, please e-mail me the file and describe the
  84. problem.
  85. X
  86. X     You will have to provide a getopt() function.
  87. This filter runs under UNIX and MS-DOS and hopefully anything else that
  88. supports ANSI-C.  To compile under HP-UX:
  89. X
  90. cc -Aa -O pclcomp.c -o pclcomp
  91. X
  92. X
  93. X     Please direct all compliments and praise to:  tony@sdd.hp.com
  94. X
  95. X     -- Tony Parkhurst
  96. X
  97. X
  98. SHAR_EOF
  99. chmod 0664 README ||
  100. echo 'restore of README failed'
  101. Wc_c="`wc -c < 'README'`"
  102. test 1508 -eq "$Wc_c" ||
  103.     echo 'README: original size 1508, current size' "$Wc_c"
  104. rm -f _shar_wnt_.tmp
  105. fi
  106. # ============= getopt.c ==============
  107. if test -f 'getopt.c' -a X"$1" != X"-c"; then
  108.     echo 'x - skipping getopt.c (File already exists)'
  109.     rm -f _shar_wnt_.tmp
  110. else
  111. > _shar_wnt_.tmp
  112. echo 'x - extracting getopt.c (Text)'
  113. sed 's/^X//' << 'SHAR_EOF' > 'getopt.c' &&
  114. #include <stdio.h>
  115. X
  116. #define index strchr
  117. X
  118. /*
  119. X * get option letter from argument vector
  120. X */
  121. int    opterr = 1,        /* useless, never set or used */
  122. X    optind = 1,        /* index into parent argv vector */
  123. X    optopt;            /* character checked for validity */
  124. char    *optarg;        /* argument associated with option */
  125. X
  126. #define BADCH    (int)'?'
  127. #define EMSG    ""
  128. #define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  129. X        fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  130. X
  131. getopt(nargc,nargv,ostr)
  132. int    nargc;
  133. char    **nargv,
  134. X    *ostr;
  135. {
  136. X    static char    *place = EMSG;    /* option letter processing */
  137. X    register char    *oli;        /* option letter list index */
  138. X    char    *index();
  139. X
  140. X    if(!*place) {            /* update scanning pointer */
  141. X        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  142. X        if (*place == '-') {    /* found "--" */
  143. X            ++optind;
  144. X            return(EOF);
  145. X        }
  146. X    }                /* option letter okay? */
  147. X    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  148. X        if(!*place) ++optind;
  149. X        tell(": illegal option -- ");
  150. X    }
  151. X    if (*++oli != ':') {        /* don't need argument */
  152. X        optarg = NULL;
  153. X        if (!*place) ++optind;
  154. X    }
  155. X    else {                /* need an argument */
  156. X        if (*place) optarg = place;    /* no white space */
  157. X        else if (nargc <= ++optind) {    /* no arg */
  158. X            place = EMSG;
  159. X            tell(": option requires an argument -- ");
  160. X        }
  161. X         else optarg = nargv[optind];    /* white space */
  162. X        place = EMSG;
  163. X        ++optind;
  164. X    }
  165. X    return(optopt);            /* dump back option letter */
  166. }
  167. X
  168. X
  169. X
  170. SHAR_EOF
  171. chmod 0444 getopt.c ||
  172. echo 'restore of getopt.c failed'
  173. Wc_c="`wc -c < 'getopt.c'`"
  174. test 1431 -eq "$Wc_c" ||
  175.     echo 'getopt.c: original size 1431, current size' "$Wc_c"
  176. rm -f _shar_wnt_.tmp
  177. fi
  178. # ============= pclcomp.1 ==============
  179. if test -f 'pclcomp.1' -a X"$1" != X"-c"; then
  180.     echo 'x - skipping pclcomp.1 (File already exists)'
  181.     rm -f _shar_wnt_.tmp
  182. else
  183. > _shar_wnt_.tmp
  184. echo 'x - extracting pclcomp.1 (Text)'
  185. sed 's/^X//' << 'SHAR_EOF' > 'pclcomp.1' &&
  186. .TH PCLCOMP 1
  187. .SH NAME
  188. pclcomp \- Compress PCL graphics files.
  189. .SH SYNOPSIS
  190. .B pclcomp
  191. [
  192. .B "-0123drsvxz"
  193. ]
  194. [
  195. .B "-n"
  196. .I num
  197. ]
  198. [
  199. .I inputfile
  200. [
  201. .I outputfile
  202. ]]
  203. .br
  204. .SH DESCRIPTION
  205. .PP
  206. .B Pclcomp
  207. compresses (or decompresses) HP-PCL (Printer Control Language) graphics data.
  208. The supported compression modes are 0 (uncompressed), 1, 2 and 3.
  209. .B Pclcomp
  210. will read files using any of the modes 0 through 3, and will output using the
  211. modes which will give the best compression.  This compressed version of
  212. the file may be sent directly to a PCL compatible printer, thus reducing
  213. I/O bandwidth.  Pictures may also be saved in compressed form, reducing
  214. disk usage.
  215. In addition, PCL "imaging" files for the PaintJet XL are also supported.
  216. .PP
  217. The options to
  218. .B pclcomp
  219. control the compression modes.  By default,
  220. .B pclcomp
  221. will use modes 0, 2 and 3, but the user may restrict which output
  222. modes it uses by specifying them on the command line with the
  223. .B -0,
  224. .B -1,
  225. .B -2
  226. and
  227. .B -3
  228. options.  To decompress a file, simply specify
  229. .B -0
  230. as the only mode to use for output.  Mode 0 (
  231. .B -0
  232. ) should always be allowed since modes 1, 2 and 3 cannot be guaranteed to
  233. be better than mode 0 for all types of pictures.
  234. .PP
  235. The
  236. .B -z
  237. option disables the zero "strip" feature.  Since most printers do 
  238. zero "filling",
  239. .B pclcomp,
  240. by default, "strips" the trailing zeros of each row (or plane) of data.
  241. Some printers or programs may require that zero "stripping" be disabled.
  242. .PP
  243. By default,
  244. .B pclcomp
  245. expects the input raster width to be 2400 pixels (8" at 300 dpi), and if it is
  246. different (e.g. PaintJet), then the raster width should be specified by
  247. the Source Raster Width escape sequence
  248. .I <esc*r#S>.
  249. However, many applications do not set the width and assume a default, therefore,
  250. the user may use the 
  251. .B -n
  252. option to
  253. .B pclcomp
  254. to specify a new default raster width.  For PaintJet (8" at 180 dpi), the
  255. number should be 1440.  If the PCL file contains the Source Raster Width
  256. escape sequence, it will override this default.  If
  257. .B pclcomp
  258. thinks that more data is coming in than the specified width, it will
  259. generate a warning, and continue processing (and perhaps truncating) data.
  260. .PP
  261. The
  262. .B -x
  263. option will cause
  264. .B pclcomp
  265. to remove any horizontal offset sequences from the data.  Only use this
  266. option if white is defined to be zero (as with LaserJets).  This will
  267. shrink the data more if modes 2 or 3 are used.
  268. .PP
  269. The
  270. .B -r
  271. option causes
  272. .B pclcomp
  273. to append a
  274. reset sequence
  275. .I "(<esc>E)"
  276. to the end of the job.
  277. .PP
  278. Use the
  279. .B "-d"
  280. option to
  281. .B pclcomp
  282. if the output is to be sent to a DeskJet printer.
  283. .PP
  284. Some applications erroneously send
  285. .I "<esc>*rB"
  286. and
  287. .I "<esc>*rA"
  288. sequences between every row of graphics data.  The 
  289. .B -s
  290. option to
  291. .B pclcomp
  292. will "strip" all 
  293. .I "<esc>*rB"
  294. sequences, and all
  295. .I "<esc>*rA"
  296. sequences after the first occurrence of this sequence.  
  297. In addition, text and control characters residing between
  298. .I "<esc>*rA"
  299. and
  300. .I "<esc>*rB"
  301. sequences will be discarded.
  302. While this will work
  303. well
  304. for many jobs, it may have problems on multi-page or complex jobs.
  305. .PP
  306. The
  307. .B -v
  308. option simply gives statistics to
  309. .I stderr
  310. about which compression modes were used.
  311. .SH EXAMPLES
  312. .nf
  313. To compress a PCL file for LaserJet III, use:
  314. X    pclcomp infile outfile
  315. X
  316. To compress a PCL file for the PaintJet (A size page at 180 dpi), use:
  317. X    pclcomp -01 -n 1440 infile outfile
  318. X
  319. To compress a PCL file for DeskJet, use:
  320. X    pclcomp -d012 infile outfile
  321. X
  322. To fully decompress a PCL file, use:
  323. X    pclcomp -0z < infile > outfile
  324. .fi
  325. .SH WARNINGS
  326. .PP
  327. The 
  328. .B -z
  329. option can cause the output to be larger than the input.
  330. .PP
  331. The 
  332. .B -s
  333. option is useful, but it can cause erroneous output.
  334. .PP
  335. The
  336. .B -x
  337. option can cause black areas on the left side of the picture on color
  338. printers.
  339. .SH AUTHOR
  340. Tony Parkhurst, Hewlett-Packard, San Diego Division  (tony@sdd.hp.com)
  341. SHAR_EOF
  342. chmod 0444 pclcomp.1 ||
  343. echo 'restore of pclcomp.1 failed'
  344. Wc_c="`wc -c < 'pclcomp.1'`"
  345. test 3851 -eq "$Wc_c" ||
  346.     echo 'pclcomp.1: original size 3851, current size' "$Wc_c"
  347. rm -f _shar_wnt_.tmp
  348. fi
  349. # ============= pclcomp.c ==============
  350. if test -f 'pclcomp.c' -a X"$1" != X"-c"; then
  351.     echo 'x - skipping pclcomp.c (File already exists)'
  352.     rm -f _shar_wnt_.tmp
  353. else
  354. > _shar_wnt_.tmp
  355. echo 'x - extracting pclcomp.c (Text)'
  356. sed 's/^X//' << 'SHAR_EOF' > 'pclcomp.c' &&
  357. /*
  358. **  Pclcomp -- PCL compression filter.
  359. **
  360. **  If you have any problems or errors to report, please send them to me:
  361. **
  362. **  Tony Parkhurst  
  363. ** 
  364. **  Email address:  tony@sdd.hp.com    -or-   hp-sdd!tony
  365. **
  366. **  Please send a copy of the file that is causing the problem, and the
  367. **  version of pclcomp you are using.
  368. **
  369. **  All suggestions and requests are welcome.
  370. */
  371. X
  372. /*
  373. X ***************************************************************************
  374. X *
  375. X * $Source: /disc/44/cgtriton/tony/filters/pclcomp/RCS/pclcomp.c,v $ 
  376. X * $Date: 91/09/13 13:56:28 $ 
  377. X * $Revision: 1.39 $
  378. X *
  379. X * Description:    Compresses pcl graphics files.
  380. X *
  381. X * Author:       Tony Parkhurst
  382. X * Created:      890427
  383. X * Language:     C
  384. X *
  385. X * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved.
  386. X *
  387. X ***************************************************************************
  388. X */
  389. X
  390. X
  391. /*
  392. X ***************************************************************************
  393. X *
  394. X * $Log:    pclcomp.c,v $
  395. X * Revision 1.39  91/09/13  13:56:28  13:56:28  tony (Tony Parkhurst)
  396. X * Added code to disable zerostrip in mode 2.
  397. X * 
  398. X * Revision 1.38  91/09/10  15:47:28  15:47:28  tony (Tony Parkhurst)
  399. X * Added include file for isdigit()
  400. X * 
  401. X * Revision 1.37  91/09/10  15:08:23  15:08:23  tony (Tony Parkhurst)
  402. X * Clamped horizontal offsets to raster widths.
  403. X * 
  404. X * Revision 1.36  91/09/10  15:04:15  15:04:15  tony (Tony Parkhurst)
  405. X * Re-vamped fraction parsing.
  406. X * 
  407. X * Revision 1.35  91/09/10  14:03:40  14:03:40  tony (Tony Parkhurst)
  408. X * Fixed potential problem with fractions.
  409. X * Removed obsolete invert flag.
  410. X * Cleaned up some comments.
  411. X * 
  412. X * Revision 1.34  91/09/10  13:21:48  13:21:48  tony (Tony Parkhurst)
  413. X * Fixed problems with data gaps  (0W instead of 0V0V0W)
  414. X * Fixed problems with horizontal offsets and mode 3 compression.
  415. X * Added option to strip horizontal offsets (zero value must be white).
  416. X * 
  417. X * Revision 1.33  91/07/18  15:18:43  15:18:43  tony (Tony Parkhurst)
  418. X * Replaced mode 2 compression routine.  Works better now.
  419. X * 
  420. X * Revision 1.32  91/07/08  11:27:24  11:27:24  tony (Tony Parkhurst)
  421. X * Enhanced the strip algorithm for merged graphics.
  422. X * (Also cleaned up some comments, couple of statements.)
  423. X * 
  424. X * Revision 1.31  91/05/30  15:18:51  15:18:51  tony (Tony Parkhurst)
  425. X * Oops, fixed it right this time.
  426. X * 
  427. X * Revision 1.30  91/05/30  15:06:20  15:06:20  tony (Tony Parkhurst)
  428. X * Added fix for negative value for <esc>*r#U.
  429. X * 
  430. X * Revision 1.29  91/05/03  10:12:30  10:12:30  tony (Tony Parkhurst)
  431. X * Small changes.
  432. X * 
  433. X * Revision 1.28  91/04/30  09:41:24  09:41:24  tony (Tony Parkhurst)
  434. X * Now puts stdin and stdout in binary mode for MSDOS.
  435. X *     Changes courtesy of Mike Slomin.
  436. X * Changed usage message a bit.
  437. X * 
  438. X * Revision 1.27  91/04/23  15:48:05  15:48:05  tony (Tony Parkhurst)
  439. X * Added handling of plus_sign in value fields.
  440. X * 
  441. X * Revision 1.26  91/04/23  09:47:11  09:47:11  tony (Tony Parkhurst)
  442. X * Pass thru unknown modes.
  443. X * 
  444. X * Revision 1.25  91/04/18  11:09:27  11:09:27  tony (Tony Parkhurst)
  445. X * Added parse for fractions in values (i.e. <esc>(s16.67H)
  446. X * 
  447. X * Revision 1.24  91/04/10  14:16:30  14:16:30  tony (Tony Parkhurst)
  448. X * strips text and control codes between <esc>*rA and <esc>*rB w/ -s option
  449. X * 
  450. X * Revision 1.23  91/04/05  14:53:25  14:53:25  tony (Tony Parkhurst)
  451. X * Added fixed for deskjet
  452. X * Also added a stripping feature.
  453. X * 
  454. X * Revision 1.22  91/04/05  08:48:53  08:48:53  tony (Tony Parkhurst)
  455. X * Added some error checkin on output for MS-DOS users.
  456. X * 
  457. X * Revision 1.21  91/04/04  12:53:32  12:53:32  tony (Tony Parkhurst)
  458. X * Replaced parser.
  459. X *    Now handles combined escape sequences.
  460. X *    Now handles downloads.
  461. X *    Now combines mode changes with data.
  462. X * 
  463. X * Revision 1.20  91/04/04  08:02:12  08:02:12  tony (Tony Parkhurst)
  464. X * Removed some test code.
  465. X * 
  466. X * Revision 1.19  91/03/25  14:38:48  14:38:48  tony (Tony Parkhurst)
  467. X * Changed defaults.
  468. X * 
  469. X * Revision 1.18  91/03/25  14:31:22  14:31:22  tony (Tony Parkhurst)
  470. X * Re-worked memory allocation stuff for funky input files.
  471. X * 
  472. X * Revision 1.17  91/03/25  13:50:19  13:50:19  tony (Tony Parkhurst)
  473. X * Use command line args for file w/o -i or -o.
  474. X * 
  475. X * Revision 1.16  91/03/04  14:23:15  14:23:15  tony (Tony Parkhurst)
  476. X * Fixed to allow ONLY mode 3 if the user really wants it.
  477. X * 
  478. X * Revision 1.15  91/03/04  14:08:23  14:08:23  tony (Tony Parkhurst)
  479. X * Added an exit(0) at the end of main.
  480. X * fixed up some zerostrip stuff.
  481. X * made mode 3 the highest priority mode.
  482. X * 
  483. X * Revision 1.14  91/02/20  13:57:27  13:57:27  tony (Tony Parkhurst)
  484. X * Changed priority a bit.
  485. X * Added some zerostripping for mode 2.
  486. X * 
  487. X * Revision 1.13  91/02/06  15:31:00  15:31:00  tony (Tony Parkhurst)
  488. X * oops.
  489. X * 
  490. X * Revision 1.12  91/02/06  14:41:28  14:41:28  tony (Tony Parkhurst)
  491. X * fixed usage message
  492. X * 
  493. X * Revision 1.11  91/02/06  14:38:10  14:38:10  tony (Tony Parkhurst)
  494. X * Added file input and output for MS-DOS.
  495. X * 
  496. X * Revision 1.10  91/02/05  17:49:23  17:49:23  tony (Tony Parkhurst)
  497. X * Fixed problem with zero stripped input.
  498. X * 
  499. X * Revision 1.9  91/02/05  16:11:39  16:11:39  tony (Tony Parkhurst)
  500. X * Removed delay code and bitfield stuff.
  501. X * 
  502. X * Revision 1.8  91/02/05  11:04:53  11:04:53  tony (Tony Parkhurst)
  503. X * Added io delay stuff for testing.
  504. X * 
  505. X * Revision 1.7  91/02/05  10:28:32  10:28:32  tony (Tony Parkhurst)
  506. X * Fix for someone specifing ONLY mode 3.
  507. X * 
  508. X * Revision 1.6  91/01/29  14:13:09  14:13:09  tony (Tony Parkhurst)
  509. X * Updated some comments.
  510. X * 
  511. X * Revision 1.5  91/01/29  13:26:24  13:26:24  tony (Tony Parkhurst)
  512. X * Cleaned up, revamped a bit.
  513. X * 
  514. X * Revision 1.4  89/11/09  15:59:16  15:59:16  tony (Tony Parkhurst)
  515. X * Fix for esc * r U coming after esc * r A.
  516. X * 
  517. X * Revision 1.3  89/10/24  11:31:12  11:31:12  tony (Tony Parkhurst)
  518. X * Added parsing of <esc>*rC
  519. X * 
  520. X * Revision 1.2  89/10/13  09:56:46  09:56:46  tony (Tony Parkhurst)
  521. X * Completely revamped by Greg G.
  522. X * 
  523. X * Revision 1.1  89/06/15  13:57:46  13:57:46  tony (Tony Parkhurst)
  524. X * Initial revision
  525. X * 
  526. X *
  527. X ***************************************************************************
  528. X */
  529. static const char copyr[]=
  530. X    "Copyright (c) 1991, Hewlett-Packard Company, all rights reserved.";
  531. X
  532. static const char author[]="Tony Parkhurst";
  533. X
  534. static const char rcs_id[]="$Header: pclcomp.c,v 1.39 91/09/13 13:56:28 tony Exp $";
  535. X
  536. static const char rev_id[]="$Revision: 1.39 $";
  537. X
  538. /*
  539. X *   This program was first a filter by Dean to compress pcl graphics.
  540. X *
  541. X *   This program now will do optimal compression using modes 0,1,2 and 3
  542. X *
  543. X *   Also, this program will take compressed input.
  544. X *
  545. X *   Input and output formats are standard pcl.
  546. X *
  547. X *   Imaging files ("Configure Image Data") are supported.
  548. X *
  549. X *   Pclcomp does not take advantage of Y-Offset for blank areas.  
  550. X *   This is because Y-Offset creates white areas, but we don't do enough
  551. X *   parsing to determine what value "white" has.  An application that
  552. X *   can assume white values could make use of this sequence.
  553. X *
  554. X *   Pclcomp does not do any of the block compression modes (4-8).
  555. X *
  556. X *   An additional enhancement would be to compare all the planes in a
  557. X *   multi-plane file (color) and if nothing changed, using mode 3, just
  558. X *   output a single <esc>*b0W.
  559. X *
  560. X *
  561. X *   Usage:  pclcomp [-v] [-0] [-1] [-2] [-3] [-z] [-n###] < infile > outfile
  562. X *
  563. X *   Pclcomp will do graphics compression based on compression modes 0, 1, 2
  564. X *   and 3.  (Mode 0 is uncompressed).  Pclcomp will accept all modes, and
  565. X *   will attempt to optimize by selecting the best output mode for each
  566. X *   row (or plane) of data.  By default, pclcomp will use all 4 modes, but
  567. X *   the user may restrict which output modes to use with the -0123 options.
  568. X *   For example, to use pclcomp for output to a PaintJet which only knows
  569. X *   modes 0 and 1 (the XL also understands modes 2 and 3), one would use:
  570. X *
  571. X *      pclcomp -01 < infile > outfile
  572. X *
  573. X *   Note:  Mode 0 should always be allowed.  None of the other modes is
  574. X *   guaranteed to be better than mode 0 in all cases.
  575. X *
  576. X *   The 'v' option tells the number of rows (planes) of data input and output
  577. X *   in the different modes (to stderr).
  578. X *
  579. X *   By default, pclcomp does zero "stripping" which is useful for PaintJet 
  580. X *   files using only modes 0 and 1, the PaintJet (and other PCL printers) 
  581. X *   will do zero "filling".  
  582. X *   NOTE: Use the 'z' option to disable zero stripping.
  583. X *
  584. X *   The 'n' option is to change the default number of pixels in a picture.
  585. X *   The proper way to set the pixel width is with the source raster width
  586. X *   sequence <esc*r#S>, but soo many applications just assume the default,
  587. X *   which is different on different printers, so I am providing this
  588. X *   command line option to set a new default.  One could also change the
  589. X *   DEFAULT constant below (make sure it is a multiple of 8).  
  590. X *   Currently it is set to 8" at 300 dpi (2400).
  591. X */
  592. X
  593. #include <stdio.h>
  594. #include <string.h>
  595. #include <ctype.h>
  596. X
  597. #ifdef MSDOS
  598. #include <fcntl.h>
  599. #endif
  600. X
  601. X
  602. /* This flag is for code that uses bitfields for 68000 systems */
  603. /* Not recommended at this time */
  604. X
  605. #define BITFIELDS 0
  606. X
  607. #define Get_Character() getchar()
  608. X
  609. #define MIN(x,y)    ( ((x) < (y)) ? (x) : (y) )
  610. X
  611. #define TRUE 1
  612. #define FALSE 0
  613. X
  614. #define ESC    27
  615. X
  616. #define DEFAULT 2400        /* default width in pixels (multiple of 8) */
  617. X
  618. #define MAXMODES  4
  619. #define MAXPLANES 8
  620. #define MAXBYTES 60000        /* now mostly meaningless, just a big number */
  621. X
  622. unsigned char    *seed_row[MAXPLANES];
  623. unsigned char    *new_row;
  624. unsigned char    *out_row[MAXMODES];
  625. unsigned int    out_size[MAXMODES];
  626. X
  627. char    memflag = FALSE;    /* set when memory has been allocated */
  628. X
  629. X
  630. char    mode0=FALSE,
  631. X    mode1=FALSE,
  632. X    mode2=FALSE,
  633. X    mode3=FALSE;
  634. X
  635. unsigned char    num_planes=1;
  636. unsigned char    curr_plane=0;
  637. X
  638. char    imaging = FALSE;        /* not imaging, so no lockout */
  639. X
  640. char    verbose = FALSE;
  641. X
  642. unsigned char    inmode = 0;        /* input compression mode */
  643. unsigned char    outmode = 0;        /* output compression mode */
  644. X
  645. unsigned int    rasterwidth=DEFAULT/8;    /* width of picture, in bytes */
  646. unsigned int    rpix = DEFAULT;        /* width of picture, in pixels */
  647. X
  648. unsigned char    zerostrip= TRUE;    /* strip trailing zeros */
  649. X
  650. unsigned int    inuse[4]={0,0,0,0}, outuse[4] = {0,0,0,0};
  651. X
  652. char    widthwarning = FALSE;    /* for trucation warning */
  653. char    firstrow = TRUE;    /* to prevent mode 3 from being first */
  654. X
  655. X
  656. struct {            /* this will hold the data for the  */
  657. X     unsigned char model;    /* configuring of image processing   */
  658. X     unsigned char pix_mode;
  659. X     unsigned char inx_bits;
  660. X     unsigned char red;
  661. X     unsigned char green;
  662. X     unsigned char blue;
  663. X     short wr;
  664. X     short wg;
  665. X     short wb;
  666. X     short br;
  667. X     short bg;
  668. X     short bb; 
  669. } imdata;
  670. X
  671. extern    unsigned char *malloc();
  672. X
  673. char    *filein = NULL, *fileout = NULL;
  674. X
  675. /*
  676. **  These variables are for the new parser.
  677. **  The new parser handles more sequences, and also deals with combined
  678. **  escape sequences better.
  679. */
  680. X
  681. int    parameter;
  682. int    group_char;
  683. int    terminator;
  684. int    old_terminator;
  685. int    value;
  686. float    fvalue;            /* fractional value */
  687. int    scanf_count;
  688. char    in_sequence = FALSE;
  689. char    pass_seq;
  690. char    plus_sign;        /* for relative values */
  691. X
  692. X
  693. /* dummy buffer */
  694. char buf[BUFSIZ];
  695. X
  696. /*
  697. **  If the printer is a DeskJet, then we must handle <esc>*rB differently
  698. **  Option '-d' will turn on this mode.
  699. */
  700. X
  701. char    deskjet = FALSE;
  702. X
  703. X
  704. /*
  705. **  Many drivers it seems put <esc>*rB<esc>*rA between each and every row
  706. **  of data.  This defeats compression mode 3 on a DeskJet, and also
  707. **  makes the PaintJet (not XL) quite slow.  This next flag "-s" on the
  708. **  command line, will attempt to do a reasonable job of stripping
  709. **  out the excess commands.
  710. **
  711. **  The in_graphics flag will be used to strip unwanted control chars from
  712. **  the file.
  713. */
  714. X
  715. char    strip_seq = FALSE;
  716. char    in_graphics = FALSE;
  717. X
  718. X
  719. /*
  720. **  Just for certain special cases, it would be nice to append an <esc>E reset
  721. **  to the end of the job.  Specify with "-r".
  722. */
  723. X
  724. char    reset_seq = FALSE;
  725. X
  726. X
  727. char    *progname;        /* to hold the program name for verbose */
  728. X
  729. /*
  730. **  Even though the horizontal offset command <esc>*b#X is obsolete, many
  731. **  drivers still use it, and it causes some interesting problems with
  732. **  mode 3 compression, so pclcomp needs to deal with it in some hopefully
  733. **  intelligent fashion, and they will get stripped if -x is used.
  734. */
  735. X
  736. int    horiz_offset = 0;
  737. X
  738. char    strip_offsets = FALSE;
  739. X
  740. X
  741. static float    Get_Frac();    /* instead of scanf */
  742. X
  743. X
  744. X
  745. /*
  746. ******************************************************************************
  747. **
  748. **                Main program.
  749. **
  750. ******************************************************************************
  751. */
  752. X
  753. main(argc, argv)
  754. int argc;
  755. char *argv[];
  756. {
  757. X  int    c,j;
  758. X  extern char *optarg;
  759. X  extern int   optind;
  760. X
  761. X    progname = argv[0];
  762. X
  763. #ifdef MSDOS
  764. X    setmode(fileno(stdin), O_BINARY);    /* Place stdin and stdout in */
  765. X    setmode(fileno(stdout), O_BINARY);    /* binary mode. (Mike Slomin)*/
  766. #endif
  767. X
  768. X    /* parse up the args here */
  769. X
  770. X  while ((c = getopt(argc, argv, "0123drsvzn:i:o:sx")) != EOF )
  771. X    switch(c){
  772. X    case '0':
  773. X            mode0 = TRUE;
  774. X            break;
  775. X    case '1':
  776. X            mode1 = TRUE;
  777. X            break;
  778. X    case '2':
  779. X            mode2 = TRUE;
  780. X            break;
  781. X    case '3':
  782. X            mode3 = TRUE;
  783. X            break;
  784. X    case 'd':
  785. X            deskjet = TRUE;
  786. X            break;
  787. X    case 'r':
  788. X            reset_seq = TRUE;
  789. X            break;
  790. X    case 's':
  791. X            strip_seq = TRUE;
  792. X            break;
  793. X    case 'v':
  794. X            verbose = TRUE;
  795. X            break;
  796. X    case 'x':
  797. X            strip_offsets = TRUE;
  798. X            break;
  799. X    case 'z':
  800. X            zerostrip = FALSE;
  801. X            break;
  802. X    case 'n':
  803. X            rpix = atoi(optarg);    /* new default */
  804. X            rasterwidth = (rpix + 7) / 8;    /* round up */
  805. X            break;
  806. X
  807. X    case 'i':
  808. X            filein = optarg;
  809. X            break;
  810. X    case 'o':
  811. X            fileout = optarg;
  812. X            break;
  813. X
  814. X    case '?':
  815. X    default:
  816. X            fprintf(stderr, 
  817. X            "Usage: %s [-0123drsvxz] [-n###] [infile [outfile]]\n",
  818. X                argv[0]);
  819. X            exit(-1);
  820. X    };
  821. X
  822. X    if ( verbose )
  823. X    {
  824. X        fprintf(stderr, "%s: %s\n", argv[0], rev_id);
  825. X    }
  826. X
  827. X
  828. X  if ( ! ( mode0 || mode1 || mode2 || mode3) )    /* any modes on? */
  829. X    mode0 = /* mode1 = */ mode2 = mode3 = TRUE;    /* 3 modes by default */
  830. X
  831. X    /*
  832. X    **  Check to see if any file args were given on the command line.
  833. X    **  Ones that were not preceded by a "-i" or "-o".
  834. X    */
  835. X
  836. X    if ( filein == NULL && optind < argc && argv[optind] != NULL )
  837. X        filein = argv[optind++];
  838. X
  839. X    if ( fileout == NULL && optind < argc && argv[optind] != NULL )
  840. X        fileout = argv[optind++];
  841. X
  842. X    /*
  843. X    **  Now open files for stdin and stdout if provided by the user.
  844. X    */
  845. X
  846. X    if ( filein != NULL )        /* new input file */
  847. X
  848. X        if ( freopen( filein, "rb", stdin ) == NULL )
  849. X        {
  850. X            fprintf(stderr,"Unable to open %s for input.\n",filein);
  851. X            exit(-42);
  852. X        }
  853. X
  854. X    if ( fileout != NULL )        /* new output file */
  855. X
  856. X        if ( freopen( fileout, "wb", stdout ) == NULL )
  857. X        {
  858. X            fprintf(stderr, "Unable to open %s for output.\n",
  859. X                fileout);
  860. X            exit(-43);
  861. X        }
  862. X
  863. X
  864. X    /*
  865. X    **
  866. X    **        This is the pcl input parsing loop.
  867. X    **
  868. X    */
  869. X
  870. X    while( ( c = getchar() ) != EOF )
  871. X    {
  872. X
  873. X        /*  Ignore all chars until an escape char  */
  874. X
  875. X        /*
  876. X        **  If we are in graphics, toss it if strip_seq is set.
  877. X        */
  878. X
  879. X        if ( c != ESC )
  880. X        {
  881. X            if ( !strip_seq || !in_graphics )
  882. X                putchar(c);    /* pass it thru */
  883. X
  884. X            continue;    /* pop to the top of the loop */
  885. X        }
  886. X
  887. X        /*
  888. X        **  Now we have an escape sequence, get the parameter char.
  889. X        */
  890. X
  891. X        parameter = getchar();
  892. X
  893. X        if ( parameter == EOF )        /* oops */
  894. X        {
  895. X            putchar ( ESC );
  896. X            fprintf(stderr, "Warning:  File ended with <esc>.\n");
  897. X            break;            /* unexpected end of input */
  898. X        }
  899. X
  900. X        /*
  901. X        **  Now check to see if it is a two character sequence.
  902. X        */
  903. X
  904. X        if ( parameter >= '0' && parameter <= '~' )
  905. X        {
  906. X            putchar ( ESC );
  907. X            putchar ( parameter );        /* pass it thru */
  908. X
  909. X            /*
  910. X            **  If the second character is an E, then we
  911. X            **  and the printer do a reset.
  912. X            */
  913. X
  914. X            if ( parameter == 'E' )
  915. X            {
  916. X                free_mem();
  917. X                curr_plane = 0;
  918. X                num_planes = 1;
  919. X                imaging = FALSE;
  920. X                inmode = 0;
  921. X                outmode = 0;
  922. X                in_graphics = FALSE;
  923. X
  924. X                /* can't do this if user gave value with -n.
  925. X                rasterwidth = DEFAULT/8;
  926. X                rpix = DEFAULT;
  927. X                */
  928. X            }
  929. X
  930. X            continue;        /* return to the top */
  931. X        }
  932. X
  933. X        /*
  934. X        **  Now check to make sure that the parameter character is
  935. X        **  within range.
  936. X        */
  937. X
  938. X        if ( parameter < '!' || parameter > '/' )
  939. X        {
  940. X            putchar ( ESC );
  941. X            putchar ( parameter );
  942. X
  943. X            fprintf(stderr, "Warning:  Invalid escape sequence.\n");
  944. X
  945. X            continue;
  946. X        }
  947. X
  948. X        /*
  949. X        **  We are only interested in certain parameters, so pass
  950. X        **  the rest of the sequences.
  951. X        */
  952. X
  953. X        /*
  954. X        **  For the moment, we are only interested in '*' (graphics)
  955. X        **  '(' and ')' (downloads).  Although we do not do anything
  956. X        **  with downloads, we need to pass the binary data thru
  957. X        **  untouched.
  958. X        **  Oops, '&' is handled too.
  959. X        */
  960. X
  961. X        if ( parameter != '*' && parameter != '(' 
  962. X            && parameter != ')' && parameter != '&' )
  963. X        {
  964. X
  965. X            /*
  966. X            **  If the "stripper" is active, we need to suspend
  967. X            **  it till graphics are re-started.
  968. X            */
  969. X
  970. X            if ( strip_seq && !in_graphics )
  971. X            {
  972. X                curr_plane = 0;
  973. X                free_mem();        /* force re-start */
  974. X            }
  975. X
  976. X            /*
  977. X            **  Pass thru the sequence intact.
  978. X            */
  979. X
  980. X            putchar ( ESC );
  981. X            putchar ( parameter );
  982. X            Flush_To_Term();        /* flush rest of seq. */
  983. X            continue;
  984. X        }
  985. X
  986. X
  987. X        /*
  988. X        **  Parameter character is in range, look for a valid group char
  989. X        */
  990. X
  991. X        group_char = getchar();
  992. X
  993. X        if ( group_char == EOF )    /* oops, ran out of input */
  994. X        {
  995. X            putchar ( ESC );
  996. X            putchar ( parameter );
  997. X
  998. X            fprintf(stderr, "Warning:  Incomplete escape sequence.\n");
  999. X            break;
  1000. X        }
  1001. X
  1002. X        /*
  1003. X        **  See if in proper range.  If it isn't, it is not an error
  1004. X        **  because the group character is optional for some sequences.
  1005. X        **  For the moment, we are not interested in those sequences,
  1006. X        **  so pass them thru.
  1007. X        */
  1008. X
  1009. X        if ( group_char < '`' || group_char > '~' )
  1010. X        {
  1011. X
  1012. X            /*
  1013. X            **  If the "stripper" is active, we need to suspend
  1014. X            **  it till graphics are re-started.
  1015. X            */
  1016. X
  1017. X            if ( strip_seq && !in_graphics )
  1018. X            {
  1019. X                curr_plane = 0;
  1020. X                free_mem();        /* force re-start */
  1021. X            }
  1022. X
  1023. X            /*
  1024. X            **  Pass thru the sequence intact.
  1025. X            */
  1026. X
  1027. X            putchar ( ESC );
  1028. X            putchar ( parameter );
  1029. X            putchar ( group_char );
  1030. X            if ( group_char < '@' || group_char > '^' )
  1031. X                Flush_To_Term();    /* pass rest of seq. */
  1032. X            continue;
  1033. X        }
  1034. X
  1035. X        /*
  1036. X        **  Now we have a valid group character, decide if we want
  1037. X        **  to deal with this escape sequence.
  1038. X        **
  1039. X        **  Sequences we want do deal with include:
  1040. X        **
  1041. X        **    <esc>*r    ** graphics
  1042. X        **    <esc>*b    ** graphics
  1043. X        **    <esc>*v    ** graphics
  1044. X        **
  1045. X        **  Sequences we must pass thru binary data:
  1046. X        **
  1047. X        **    <esc>*c    ** pattern
  1048. X        **    <esc>*s    ** download dither
  1049. X        **    <esc>*t    ** obsolete
  1050. X        **    <esc>(f    ** download char set
  1051. X        **    <esc>(s    ** download char
  1052. X        **    <esc>)s    ** download font
  1053. X        **    <esc>&a    ** logical page
  1054. X        **    <esc>&l    ** obsolete
  1055. X        **
  1056. X        */
  1057. X
  1058. X        if (  ( parameter == '*'
  1059. X            && group_char != 'r' && group_char != 'b' 
  1060. X            && group_char != 'v' && group_char != 'c' 
  1061. X            && group_char != 't' && group_char != 's' )
  1062. X           || ( parameter == '&'
  1063. X            && group_char != 'a' && group_char != 'l' )
  1064. X           || ( parameter == '(' 
  1065. X            && group_char != 'f' && group_char != 's' )
  1066. X           || ( parameter == ')' && group_char != 's' ) )
  1067. X        {
  1068. X            /*
  1069. X            **  Definately not interested in the sequence.
  1070. X            */
  1071. X
  1072. X            /*
  1073. X            **  If the "stripper" is active, we need to suspend
  1074. X            **  it till graphics are re-started.
  1075. X            */
  1076. X
  1077. X            if ( strip_seq && !in_graphics )
  1078. X            {
  1079. X                curr_plane = 0;
  1080. X                free_mem();        /* force re-start */
  1081. X            }
  1082. X
  1083. X            /*
  1084. X            **  Pass thru the sequence intact.
  1085. X            */
  1086. X
  1087. X            putchar ( ESC );
  1088. X            putchar ( parameter );
  1089. X            putchar ( group_char );
  1090. X            Flush_To_Term();
  1091. X            continue;
  1092. X        }
  1093. X
  1094. X
  1095. X        /*
  1096. X        **  If the sequence is <esc>&a#H, it will have gotten past
  1097. X        **  the above, but we need to suspend the "stripper" if
  1098. X        **  it is active, because the CAP is getting moved.
  1099. X        **
  1100. X        **  The <esc>*p#X/Y sequences will have been filtered
  1101. X        **  thru just above (<esc>*p is not a needed group).
  1102. X        */
  1103. X
  1104. X        if ( strip_seq && parameter != '*' && !in_graphics )
  1105. X        {
  1106. X            curr_plane = 0;
  1107. X            free_mem();        /* force re-start */
  1108. X        }
  1109. X
  1110. X
  1111. X        /*
  1112. X        **  Now set up a pass thru flag so we can ignore the entire
  1113. X        **  sequences of some of these.
  1114. X        */
  1115. X
  1116. X        if ( parameter != '*' )
  1117. X            pass_seq = TRUE;
  1118. X
  1119. X        else if ( group_char == 'c' || group_char == 't' 
  1120. X               || group_char == 's' )
  1121. X
  1122. X            pass_seq = TRUE;
  1123. X        else
  1124. X            pass_seq = FALSE;
  1125. X
  1126. X
  1127. X        /*
  1128. X        **  Now we have a sequence that we are definately interested in.
  1129. X        **
  1130. X        **  Get the value field and terminator, and loop until final
  1131. X        **  terminator is found.
  1132. X        */
  1133. X
  1134. X        do
  1135. X        {
  1136. X            /* first see if the value has a plus sign */
  1137. X
  1138. X            scanf_count = scanf(" + %d", &value );
  1139. X
  1140. X            if ( scanf_count == 1 )
  1141. X
  1142. X                plus_sign = TRUE;
  1143. X            else
  1144. X            {
  1145. X                plus_sign = FALSE;
  1146. X
  1147. X                scanf_count = scanf(" %d", &value );
  1148. X
  1149. X                if ( scanf_count == 0 )
  1150. X                    value = 0;        /* by default */
  1151. X            }
  1152. X
  1153. X            /*
  1154. X            **  I wonder if I will get bitten by a trailing
  1155. X            **  space character right here?
  1156. X            */
  1157. X
  1158. X            terminator = getchar();
  1159. X
  1160. X            /*
  1161. X            **  Check for a fractional component.
  1162. X            */
  1163. X
  1164. X            fvalue = 0.0;
  1165. X
  1166. X            if ( terminator == '.' )
  1167. X            {
  1168. X                fvalue = Get_Frac();
  1169. X
  1170. X                /*
  1171. X                **  Now get real terminator.
  1172. X                */
  1173. X
  1174. X                terminator = getchar();
  1175. X            }
  1176. X
  1177. X
  1178. X            if ( terminator == EOF )    /* barf */
  1179. X            {
  1180. X                fprintf(stderr, 
  1181. X                "Warning:  Incomplete sequence at EOF.\n");
  1182. X                break;
  1183. X            }
  1184. X
  1185. X            /*
  1186. X            **  If the pass_seq flag is set, then just pass
  1187. X            **  it thru to stdout until a 'W' is found.
  1188. X            */
  1189. X
  1190. X            if ( pass_seq )
  1191. X            {
  1192. X                /*
  1193. X                **  If not in sequence, then we output esc
  1194. X                **  otherwise, output the saved terminator.
  1195. X                */
  1196. X
  1197. X                if ( !in_sequence )
  1198. X                {
  1199. X                    in_sequence = TRUE;
  1200. X                    putchar ( ESC );
  1201. X                    putchar ( parameter );
  1202. X                    putchar ( group_char );
  1203. X                } else
  1204. X                {
  1205. X                    putchar ( old_terminator );
  1206. X                }
  1207. X
  1208. X                /* now pass the value */
  1209. X
  1210. X                if ( plus_sign )
  1211. X                    putchar('+');
  1212. X
  1213. X                /*
  1214. X                **  See if there was a non-zero fraction.
  1215. X                */
  1216. X
  1217. X                if ( fvalue != 0.0 )
  1218. X                {
  1219. X                    if ( value < 0 )
  1220. X                    {
  1221. X                        putchar('-');
  1222. X                        value = -value;
  1223. X                    }
  1224. X
  1225. X                    fvalue += value;
  1226. X
  1227. X                    printf("%g", fvalue);
  1228. X
  1229. X                } else if ( scanf_count )
  1230. X                    printf("%0d", value);
  1231. X                
  1232. X                /*
  1233. X                **  We save the terminator, because we may
  1234. X                **  need to change it to upper case.
  1235. X                */
  1236. X
  1237. X                old_terminator = terminator;
  1238. X
  1239. X                /* if binary data, pass it thru */
  1240. X
  1241. X                if ( terminator == 'W' )    /* aha */
  1242. X                {
  1243. X                    putchar ( terminator );
  1244. X                    in_sequence = FALSE;    /* terminates */
  1245. X                    Flush_Bytes ( value );    /* pass data */
  1246. X                }
  1247. X
  1248. X                continue;
  1249. X            }
  1250. X
  1251. X            /*
  1252. X            **  Ok, this is a sequence we want to pay attention to.
  1253. X            **
  1254. X            **  Do_Graphics returns TRUE if we need to pass seq.
  1255. X            **
  1256. X            **  Note:  Do_Graphics modifies the parser vars such
  1257. X            **         as in_sequence.  This is because it may
  1258. X            **         have to output stuff directly.
  1259. X            */
  1260. X
  1261. X            if ( Do_Graphics ( group_char, value, terminator ) )
  1262. X            {
  1263. X                /*
  1264. X                **  If not in sequence, then we output esc
  1265. X                **  otherwise, output the saved terminator.
  1266. X                */
  1267. X
  1268. X                if ( !in_sequence )
  1269. X                {
  1270. X                    in_sequence = TRUE;
  1271. X                    putchar ( ESC );
  1272. X                    putchar ( parameter );
  1273. X                    putchar ( group_char );
  1274. X                } else
  1275. X                {
  1276. X                    putchar ( old_terminator );
  1277. X                }
  1278. X
  1279. X                /* now pass the value */
  1280. X
  1281. X                if ( plus_sign )
  1282. X                    putchar('+');
  1283. X
  1284. X                /*
  1285. X                **  See if there was a non-zero fraction.
  1286. X                */
  1287. X
  1288. X                if ( fvalue != 0.0 )
  1289. X                {
  1290. X                    if ( value < 0 )
  1291. X                    {
  1292. X                        putchar('-');
  1293. X                        value = -value;
  1294. X                    }
  1295. X
  1296. X                    fvalue += value;
  1297. X
  1298. X                    printf("%g", fvalue);
  1299. X
  1300. X                } else if ( scanf_count )
  1301. X                    printf("%0d", value);
  1302. X
  1303. X                /*
  1304. X                **  We save the terminator, because we may
  1305. X                **  need to change it to upper case.
  1306. X                */
  1307. X
  1308. X                old_terminator = terminator;
  1309. X            }
  1310. X
  1311. X        } while ( terminator >= '`' && terminator <= '~' );
  1312. X
  1313. X        /*
  1314. X        ** The oppsite test (above) may be more appropriate.  That is, 
  1315. X        ** !(terminator >= '@' && terminator <= '^').
  1316. X        */
  1317. X        
  1318. X        /*
  1319. X        **  If we were in a sequence, then we must terminate it.
  1320. X        **  If it was lower case, then it must be uppered.
  1321. X        */
  1322. X
  1323. X        if ( in_sequence )
  1324. X        {
  1325. X            putchar ( terminator & 0xdf );        /* a ==> A */
  1326. X            in_sequence = FALSE;
  1327. X        }
  1328. X    }
  1329. X    
  1330. X
  1331. X    /*
  1332. X    **  If the user wants a reset, give him one.
  1333. X    */
  1334. X
  1335. X    if ( reset_seq )
  1336. X    {
  1337. X        putchar ( ESC );
  1338. X        putchar ( 'E' );
  1339. X    }
  1340. X
  1341. X
  1342. X    /*
  1343. X    **  Finished up, so print stats and close output file.
  1344. X    */
  1345. X
  1346. X    fclose(stdout);
  1347. X
  1348. X
  1349. X    if ( verbose )
  1350. X    {
  1351. X        for(j = 0; j < 4; j++)
  1352. X            fprintf(stderr,"Rows in mode %1d: %d\n", j, inuse[j]);
  1353. X        for(j = 0; j < 4; j++)
  1354. X            fprintf(stderr,"Rows out mode %1d: %d\n", j, outuse[j]);
  1355. X    }
  1356. X
  1357. X    exit(0);
  1358. }
  1359. X
  1360. X
  1361. /*
  1362. **  Do_Graphics() takes the graphics escape sequence and performs the
  1363. **  necessary functions.
  1364. **  TRUE is returned if the escape sequence needs to be passed to the output.
  1365. */
  1366. X
  1367. int    Do_Graphics( group, num, terminator )
  1368. int    group, num, terminator;
  1369. {
  1370. X    /*  first look at vW  */
  1371. X
  1372. X    if ( group == 'v' )
  1373. X
  1374. X        if ( terminator != 'W' )
  1375. X            
  1376. X            return ( TRUE );    /* pass it thru */
  1377. X        else
  1378. X        {
  1379. X            if ( !in_sequence )
  1380. X            {
  1381. X                putchar ( ESC );
  1382. X                putchar ( parameter );
  1383. X                putchar ( group );
  1384. X            } else
  1385. X                putchar ( old_terminator );
  1386. X
  1387. X            in_sequence = FALSE;        /* terminating */
  1388. X
  1389. X            printf("%0d", num);
  1390. X            putchar ( terminator );
  1391. X
  1392. X            free_mem();    /* reset memory */
  1393. X
  1394. X            imaging++;
  1395. X
  1396. X            fread(&imdata, MIN(num, 18), 1, stdin);
  1397. X            fwrite(&imdata, MIN(num, 18), 1, stdout);
  1398. X
  1399. X            num -= MIN(num, 18);
  1400. X
  1401. X            /* copy rest of unknown data */
  1402. X
  1403. X            if ( num > 0 )
  1404. X                Flush_Bytes(num);
  1405. X
  1406. X
  1407. X            switch(imdata.pix_mode){
  1408. X                case 0x00:
  1409. X                    rasterwidth = (rpix + 7)/8;
  1410. X                    num_planes = imdata.inx_bits;
  1411. X                    break;
  1412. X                case 0x01:
  1413. X                    rasterwidth = rpix*imdata.inx_bits/8;
  1414. X                    break;
  1415. X                case 0x02:
  1416. X                    rasterwidth = (rpix + 7)/8;
  1417. X                    num_planes =imdata.red + imdata.green +
  1418. X                                imdata.blue;
  1419. X                    break;
  1420. X                case 0x03:
  1421. X                    rasterwidth = (imdata.red +
  1422. X                                   imdata.green +
  1423. X                                   imdata.blue)*rpix/8;
  1424. X                    break;
  1425. X            }
  1426. X
  1427. X            return ( FALSE );
  1428. X        }
  1429. X
  1430. X    /*
  1431. X    **  Now deal with <esc>*r stuff
  1432. X    */
  1433. X
  1434. X    if ( group == 'r' )
  1435. X    {
  1436. X        switch ( terminator )
  1437. X        {
  1438. X            case 'A':
  1439. X            case 'a':
  1440. X
  1441. X                /* Enter graphics mode, enable stripping */
  1442. X
  1443. X                in_graphics = TRUE;
  1444. X
  1445. X                /* if user wants to strip redundant seq */
  1446. X                if ( strip_seq && memflag )
  1447. X                    return( FALSE );
  1448. X
  1449. X                curr_plane=0;
  1450. X                zero_seeds();    /* may allocate mem */
  1451. X                break;
  1452. X
  1453. X            case 'C':
  1454. X            case 'c':
  1455. X
  1456. X                /* Exit graphics, disable stripping */
  1457. X
  1458. X                in_graphics = FALSE;
  1459. X
  1460. X                if ( strip_seq )
  1461. X                    return( FALSE );
  1462. X
  1463. X                inmode = 0;
  1464. X                outmode = 0;
  1465. X
  1466. X                free_mem();
  1467. X                curr_plane=0;
  1468. X                break;
  1469. X
  1470. X            case 'B':
  1471. X            case 'b':
  1472. X
  1473. X                /* Exit graphics, disable stripping */
  1474. X
  1475. X                in_graphics = FALSE;
  1476. X
  1477. X                if ( strip_seq )
  1478. X                    return( FALSE );
  1479. X
  1480. X                if ( deskjet )    /* B resets modes on DJ */
  1481. X                {
  1482. X                    inmode = 0;
  1483. X                    outmode = 0;
  1484. X                }
  1485. X                free_mem();
  1486. X                curr_plane=0;
  1487. X                break;
  1488. X
  1489. X            case 'S':
  1490. X            case 's':
  1491. X
  1492. X                /* free mem in case widths changed */
  1493. X                free_mem();
  1494. X
  1495. X                rpix = num;
  1496. X
  1497. X                if (imaging){
  1498. X                    switch(imdata.pix_mode)
  1499. X                    {
  1500. X                        case 0x00:
  1501. X                            rasterwidth=(rpix+7)/8;
  1502. X                            break;
  1503. X                        case 0x01:
  1504. X                            rasterwidth = 
  1505. X                             rpix*imdata.inx_bits/8;
  1506. X                            break;
  1507. X                        case 0x02:
  1508. X                            rasterwidth=(rpix+7)/8;
  1509. X                            break;
  1510. X                        case 0x03:
  1511. X                            rasterwidth = 
  1512. X                              (imdata.red 
  1513. X                              + imdata.green
  1514. X                              + imdata.blue)*rpix/8;
  1515. X                            break;
  1516. X                    }
  1517. X                } else
  1518. X                    rasterwidth = (num + 7) / 8;
  1519. X                break;
  1520. X
  1521. X            case 'T':
  1522. X            case 't':
  1523. X                break;
  1524. X
  1525. X            case 'U':
  1526. X            case 'u':
  1527. X                curr_plane=0;
  1528. X                free_mem();    /* if ESC*rA came first */
  1529. X
  1530. X                /*  num can be negative */
  1531. X
  1532. X                if ( num < 0 )
  1533. X                    num_planes= -num;
  1534. X                else
  1535. X                    num_planes = num;
  1536. X
  1537. X                imaging = FALSE;    /* goes off */
  1538. X                break;
  1539. X
  1540. X            default:
  1541. X                break;
  1542. X        }
  1543. X
  1544. X        return ( TRUE );        /* pass sequence on */
  1545. X
  1546. X    }    /* group r */
  1547. X
  1548. X    /*
  1549. X    **  Last and final group 'b'.  All the graphics data comes thru here.
  1550. X    */
  1551. X
  1552. X
  1553. X    switch ( terminator )
  1554. X    {
  1555. X           case 'm':
  1556. X           case 'M':
  1557. X            inmode = num;
  1558. X            return ( FALSE );    /* we do NOT pass this */
  1559. X            break;
  1560. X
  1561. X           /*
  1562. X           **  <esc>*b#X is obsolete, but I need to use it.
  1563. X           **  In addition, they will not get passed thru.
  1564. X           */
  1565. X
  1566. X           case 'x':
  1567. X           case 'X':
  1568. X            /*
  1569. X            **  Compute in bytes, rounding down.
  1570. X            */
  1571. X
  1572. X            horiz_offset = num / 8;
  1573. X
  1574. X            if ( horiz_offset < 0 )        /* just in case */
  1575. X                horiz_offset = 0;
  1576. X
  1577. X            if ( strip_offsets || horiz_offset == 0 )
  1578. X                return ( FALSE );    /* do not pass seq */
  1579. X
  1580. X            break;
  1581. X
  1582. X           case 'y':
  1583. X           case 'Y':
  1584. X            /* zero only if allocated */
  1585. X            if ( memflag )
  1586. X                zero_seeds();
  1587. X            break;
  1588. X
  1589. X           case 'W':
  1590. X            if(!memflag)
  1591. X                zero_seeds();        /* get memory */
  1592. X
  1593. X            /* fire up sequence */
  1594. X
  1595. X            if ( !in_sequence )
  1596. X            {
  1597. X                putchar ( ESC );
  1598. X                putchar ( parameter );
  1599. X                putchar ( group );
  1600. X            } else
  1601. X                putchar ( old_terminator );
  1602. X
  1603. X            in_sequence = FALSE;        /* terminating */
  1604. X
  1605. X            /*
  1606. X            **  Check to see if we are expecting another plane.
  1607. X            */
  1608. X
  1609. X            if(curr_plane < num_planes) 
  1610. X            {
  1611. X                /*
  1612. X                **  If the input file does not have all the
  1613. X                **  expected planes  (i.e., <esc>*b0W instead
  1614. X                **  of <esc>*b0V<esc>*b0V<esc>*b0W), then
  1615. X                **  special handling is needed.
  1616. X                */
  1617. X
  1618. X                if( curr_plane + 1 < num_planes )
  1619. X                {
  1620. X                    Process_Gap ( num );
  1621. X
  1622. X                } else        /* don't worry, be happy */
  1623. X
  1624. X                    Process(num, 'W');
  1625. X
  1626. X            } else        /* oops, too many planes of data */
  1627. X
  1628. X                Process_extra(num,'W');   
  1629. X
  1630. X            curr_plane=0;
  1631. X
  1632. X            return ( FALSE );
  1633. X
  1634. X            break;
  1635. X
  1636. X           case 'V':
  1637. X            if(!memflag)
  1638. X                zero_seeds();        /* get memory */
  1639. X            
  1640. X            /*
  1641. X            **  If curr_plane is the last plane, this should
  1642. X            **  be a 'W', not a 'V'.  I could change it,
  1643. X            **  then I would fix Process_extra() to not output
  1644. X            **  anything as the 'W' was already sent.
  1645. X            */
  1646. X
  1647. X            if( curr_plane < num_planes ) 
  1648. X            {
  1649. X                /* fire up sequence */
  1650. X
  1651. X                if ( !in_sequence )
  1652. X                {
  1653. X                    putchar ( ESC );
  1654. X                    putchar ( parameter );
  1655. X                    putchar ( group );
  1656. X                } else
  1657. X                    putchar ( old_terminator );
  1658. X
  1659. X                in_sequence = FALSE;    /* terminating */
  1660. X            
  1661. X
  1662. X                Process(num, 'V');
  1663. X                curr_plane++;
  1664. X            } else
  1665. X                Process_extra(num,'V');
  1666. X
  1667. X            return ( FALSE );
  1668. X
  1669. X            break;
  1670. X
  1671. X        default:
  1672. X            break;
  1673. X    }
  1674. X
  1675. X    return ( TRUE );        /* pass sequence */
  1676. }
  1677. X
  1678. X
  1679. /*
  1680. **  Flush_To_Term() simply passes thru input until a valid terminator
  1681. **  character is found.  This is for unwanted escape sequences.
  1682. */
  1683. X
  1684. Flush_To_Term()
  1685. {
  1686. X    int    c;
  1687. X
  1688. X    do
  1689. X    {
  1690. X        c = getchar();
  1691. X
  1692. X        if ( c == EOF )            /* this is a problem */
  1693. X            return;
  1694. X        
  1695. X        putchar ( c );
  1696. X
  1697. X    } while ( c < '@' || c > '^' );
  1698. }
  1699. X
  1700. X
  1701. /*
  1702. **  Flush_Bytes() simply transfers so many bytes directly from input to output.
  1703. **  This is used to pass thru binary data that we are not interested in so that
  1704. **  it will not confuse the parser.  I.e. downloads.
  1705. */
  1706. X
  1707. Flush_Bytes( num )
  1708. unsigned int    num;
  1709. {
  1710. X    int    bnum;
  1711. X
  1712. X    while ( num > 0 )
  1713. X    {
  1714. X        bnum = MIN ( BUFSIZ, num );
  1715. X
  1716. X        fread( buf, 1, bnum, stdin );
  1717. X
  1718. X        if ( fwrite( buf, 1, bnum, stdout ) < bnum )
  1719. X
  1720. X            /* check for error and exit */
  1721. X
  1722. X            if ( ferror(stdout) )
  1723. X            {
  1724. X                perror("Output error");
  1725. X                exit(-2);
  1726. X            }
  1727. X
  1728. X        num -= bnum;
  1729. X    }
  1730. }
  1731. X
  1732. X
  1733. X
  1734. X
  1735. /*----------------------------------------*/
  1736. X
  1737. /*
  1738. **    Zero_seeds() will allocate and initialize memory.
  1739. **    If memory has already been allocated, then it will just initialize it.
  1740. */
  1741. X
  1742. X
  1743. zero_seeds()
  1744. {
  1745. X    int r;
  1746. X
  1747. X    /* first allocate and init seed_rows for number of planes. */
  1748. X
  1749. X    for ( r = 0; r < num_planes ; r++)
  1750. X    {
  1751. X        if(!memflag)
  1752. X        {
  1753. X            seed_row[r] = (unsigned char *) malloc(rasterwidth);
  1754. X
  1755. X            if ( seed_row[r] == NULL )
  1756. X            {
  1757. X                fprintf(stderr, "Out of memory.\n");
  1758. X                exit(-3);
  1759. X            }
  1760. X        }
  1761. X
  1762. X        /* zero seeds for mode 3 */
  1763. X
  1764. X        memset(seed_row[r], 0, rasterwidth);
  1765. X    }
  1766. X
  1767. X
  1768. X    if(!memflag)
  1769. X    {
  1770. X        new_row = (unsigned char *) malloc(rasterwidth);
  1771. X
  1772. X        if ( new_row == NULL )
  1773. X        {
  1774. X            fprintf(stderr, "Out of memory.\n");
  1775. X            exit(-3);
  1776. X        }
  1777. X
  1778. X        for(r=0; r<MAXMODES; r++)
  1779. X        {
  1780. X            /* 2 * width is needed for modes 1, 2 and 3 */
  1781. X
  1782. X            out_row[r] = (unsigned char *) malloc(2 * rasterwidth);
  1783. X
  1784. X            if ( out_row[r] == NULL )
  1785. X            {
  1786. X                fprintf(stderr, "Out of memory.\n");
  1787. X                exit(-3);
  1788. X            }
  1789. X        }
  1790. X
  1791. X    }
  1792. X
  1793. X    memset(new_row, 0, rasterwidth);
  1794. X
  1795. X    memflag = TRUE;            /* memory is in place */
  1796. }
  1797. X
  1798. X
  1799. /* this routine if for incomplete transfers of data */
  1800. X
  1801. zero_upper(plane)
  1802. int    plane;
  1803. {
  1804. X    int i;
  1805. X
  1806. X    /* assume memory already present */
  1807. X
  1808. X    for ( i = plane; i < num_planes; i++)
  1809. X        memset(seed_row[i], 0, rasterwidth);
  1810. }
  1811. X
  1812. X
  1813. /*
  1814. **  Process() manages the decompression and re-compression of data.
  1815. */
  1816. X
  1817. Process(inbytes, terminator)
  1818. int inbytes, terminator;
  1819. {
  1820. X
  1821. X    int insize;
  1822. X    int minmode = 0;
  1823. X
  1824. X    inuse[inmode]++;
  1825. X
  1826. X    /*
  1827. X    **  Clamp horizontal offset to the rasterwidth for safety.
  1828. X    */
  1829. X
  1830. X    if ( horiz_offset > rasterwidth )
  1831. X
  1832. X        horiz_offset = rasterwidth;
  1833. X
  1834. X    /*
  1835. X    **  Zero out horiz_offset bytes in new_row.
  1836. X    */
  1837. X
  1838. X    if ( horiz_offset )
  1839. X
  1840. X        memset ( new_row, 0, horiz_offset );
  1841. X
  1842. X
  1843. X    switch ( inmode ) {
  1844. X
  1845. X    case 0:
  1846. X        if ( !widthwarning && inbytes > rasterwidth )
  1847. X        {
  1848. X            /* This is likely to result in data truncation. */
  1849. X            widthwarning = TRUE;
  1850. X            fprintf(stderr,"Warning: Input pixel width exceeds expected width.\n");
  1851. X        }
  1852. X
  1853. X        insize = Mode_0_Graphics( inbytes, rasterwidth - horiz_offset,
  1854. X                new_row + horiz_offset);
  1855. X        break;
  1856. X    case 1:
  1857. X        insize = Mode_1_Graphics( inbytes, rasterwidth - horiz_offset,
  1858. X                new_row + horiz_offset);
  1859. X        break;
  1860. X    case 2:
  1861. X        insize = Mode_2_Graphics( inbytes, rasterwidth - horiz_offset,
  1862. X                new_row + horiz_offset);
  1863. X        break;
  1864. X    case 3:
  1865. X        memcpy(new_row, seed_row[curr_plane], rasterwidth);
  1866. X
  1867. X        if ( horiz_offset )
  1868. X            memset ( new_row, 0, MIN( horiz_offset, rasterwidth ) );
  1869. X
  1870. X        insize = Mode_3_Graphics(inbytes, rasterwidth - horiz_offset,
  1871. X                new_row + horiz_offset);
  1872. X        break;
  1873. X
  1874. X    default:        /* unknown mode? */
  1875. X
  1876. X        /*  Don't know what to do about seed rows, pass stuff thru */
  1877. X
  1878. X        fprintf(stderr, "%s: Unsupported compression mode %d.\n",
  1879. X            progname, inmode );
  1880. X
  1881. X        ChangeMode(inmode);    /* go to that mode */
  1882. X
  1883. X        /* <esc>*b has already been output */
  1884. X
  1885. X        printf("%1d%c", inbytes, terminator);
  1886. X
  1887. X        Flush_Bytes( inbytes );
  1888. X
  1889. X        firstrow = TRUE;        /* pop it out of mode 3 */
  1890. X
  1891. X        /*  Go ahead and clear the seed rows if present  */
  1892. X        if ( memflag )
  1893. X            zero_seeds();
  1894. X
  1895. X        return;
  1896. X
  1897. X    }
  1898. X
  1899. X    /*
  1900. X    **  We need to account for the horizontal offset, but if strip_offsets
  1901. X    **  is on, then assume that zero is white.
  1902. X    */
  1903. X
  1904. X    if ( strip_offsets )
  1905. X        horiz_offset = 0;
  1906. X
  1907. X
  1908. X    if ( mode0 )
  1909. X        /* actually, this is redundant since new_row is mode 0 */
  1910. X        out_size[0] = Output_0( new_row + horiz_offset, out_row[0], 
  1911. X                rasterwidth - horiz_offset );
  1912. X    else
  1913. X        out_size[0] = MAXBYTES+1;
  1914. X
  1915. X    if ( mode1 )
  1916. X        out_size[1] = Output_1( new_row + horiz_offset, out_row[1], 
  1917. X                rasterwidth - horiz_offset );
  1918. X    else
  1919. X        out_size[1] = MAXBYTES+1;
  1920. X
  1921. X    if ( mode2 )
  1922. X        out_size[2] = Output_2( new_row + horiz_offset, out_row[2], 
  1923. X                rasterwidth - horiz_offset );
  1924. X    else
  1925. X        out_size[2] = MAXBYTES+1;
  1926. X
  1927. X    if ( mode3 )
  1928. X        out_size[3] = Output_3( seed_row[curr_plane] + horiz_offset, 
  1929. X                new_row + horiz_offset, out_row[3], 
  1930. X                rasterwidth - horiz_offset );
  1931. X    else
  1932. X        out_size[3] = MAXBYTES+1;
  1933. X    
  1934. X
  1935. X    /*
  1936. X    **  Obsolete comment:
  1937. X    **
  1938. X    **  Now determine which mode will give the best output.  Note that it
  1939. X    **  takes 5 bytes to change modes, so we penalize all modes that are
  1940. X    **  not the current output by 5 bytes.  This is to discourage changing
  1941. X    **  unless the benifit is worth it.  The exception to this rule is
  1942. X    **  mode 3.  We want to encourage going to mode 3 because of the seed
  1943. X    **  row behaviour.  That is, if we have a simple picture that does
  1944. X    **  not change much, and say each of the sizes for modes 1 and 2 always
  1945. X    **  comes out to 4 bytes of data, then if we add 5 to mode 3 each time,
  1946. X    **  it would never get selected.  But, we remove the penalty, and if
  1947. X    **  mode 3 is selected (0 bytes of data needed for mode 3), then each
  1948. X    **  succesive row only needs 0 bytes of data.  For a 300 dpi A size
  1949. X    **  picture with 3 data planes, this could be a savings of 37k bytes.
  1950. X    */
  1951. X
  1952. X    /*
  1953. X    **  With the new parser, the output to change modes is now only
  1954. X    **  2 bytes, since it gets combined with the *b#W sequence.
  1955. X    **  So, I decided to ignore the switching penalty.
  1956. X    */
  1957. X
  1958. X    /*
  1959. X    **  Due to a possible bug in PaintJet XL, don't allow mode 3 to be
  1960. X    **  selected for the first row of output.  But do allow it if the
  1961. X    **  user has no other mode selected.
  1962. X    */
  1963. X
  1964. X    if ( firstrow && (mode0 || mode1 || mode2) )
  1965. X    {
  1966. X        out_size[3] = MAXBYTES+1;    /* disable mode 3 for now */
  1967. X
  1968. X        if ( terminator == 'W' )    /* last plane? */
  1969. X            firstrow = FALSE;    /* no longer first row */
  1970. X    }
  1971. X
  1972. X
  1973. X    minmode = 3;
  1974. X
  1975. X    if ( out_size[2] < out_size[minmode] )
  1976. X        minmode = 2;
  1977. X
  1978. X    if ( out_size[1] < out_size[minmode] )
  1979. X        minmode = 1;
  1980. X
  1981. X    if ( out_size[0] < out_size[minmode] )
  1982. X        minmode = 0;
  1983. X
  1984. X
  1985. X                    /* I may remove this sometime */
  1986. X    if ( minmode != outmode )
  1987. X        if ( out_size[minmode] == out_size[outmode] )
  1988. X            minmode = outmode;
  1989. X
  1990. X
  1991. X    outuse[minmode]++;
  1992. X
  1993. X    if ( outmode != minmode )
  1994. X        ChangeMode( minmode );
  1995. X    
  1996. X    /* <esc>*b has already been output */
  1997. X
  1998. X    printf("%1d%c", out_size[minmode], terminator);
  1999. X
  2000. X    if ( fwrite( out_row[minmode], 1, out_size[minmode], stdout) < 
  2001. X                            out_size[minmode] )
  2002. X
  2003. X        /* check for error and exit */
  2004. X
  2005. X        if ( ferror(stdout) )
  2006. X        {
  2007. X            perror("Output error");
  2008. X            exit(-2);
  2009. X        }
  2010. X
  2011. X
  2012. X    memcpy(seed_row[curr_plane], new_row, rasterwidth);
  2013. X
  2014. X    /*
  2015. X    **  Now clear horizontal offset for next plane.
  2016. X    */
  2017. X
  2018. X    horiz_offset = 0;
  2019. X
  2020. }
  2021. X
  2022. X
  2023. /*
  2024. **  Process_Gap() is to handle the case where less planes are sent for a
  2025. **  row than we are expecting.  For example, if we are expecting 3 planes
  2026. **  per row, and the driver decides to take a short cut for blank areas and
  2027. **  send only the final 'W'  ( <esc>*b0W instead of the complete <esc>*b0V
  2028. **  <esc>*b0V <esc>*b0W), then we have to do some special handling for mode
  2029. **  3 seed rows.
  2030. **
  2031. **  The terminator is not needed as a parameter since we know that it must
  2032. **  be 'W' to get into this routine.
  2033. */
  2034. X
  2035. Process_Gap(bytes)
  2036. int    bytes;
  2037. {
  2038. X    char    save0, save1, save2, save3;
  2039. X
  2040. X    /*
  2041. X    **  If the input file does not have all the expected planes  
  2042. X    **  (i.e., <esc>*b0W instead **  of <esc>*b0V<esc>*b0V<esc>*b0W), 
  2043. X    **  then special handling is needed.
  2044. X    **
  2045. X    **  4 cases are handled:
  2046. X    **
  2047. X    **  input mode  output mode   extra action
  2048. X    **  ----------  -----------   ------------
  2049. X    **
  2050. X    **    non-3       non-3       zero seeds
  2051. X    **
  2052. X    **      3           3         do nothing
  2053. X    **
  2054. X    **    non-3         3         zero seeds & extra output
  2055. X    **
  2056. X    **      3         non-3       extra output
  2057. X    **
  2058. X    **  Note:  We don't know what the output
  2059. X    **  mode will be before we call Process(),
  2060. X    **  so we must force the modes.
  2061. X    */
  2062. X
  2063. X    /*
  2064. X    **  Save output modes in case we need to manipulate them.
  2065. X    */
  2066. X
  2067. X    save0 = mode0;
  2068. X    save1 = mode1;
  2069. X    save2 = mode2;
  2070. X    save3 = mode3;
  2071. X
  2072. X
  2073. X    if ( inmode != 3 )
  2074. X    {
  2075. X        /*
  2076. X        **  Force output to non-3
  2077. X        **  to do as little as possible.
  2078. X        */
  2079. X
  2080. X        if ( mode0 || mode1 || mode2 )
  2081. X        {
  2082. X            mode3 = FALSE;
  2083. X
  2084. X            Process(bytes, 'W');
  2085. X
  2086. X            mode3 = save3;        /* restore mode 3 */
  2087. X
  2088. X            zero_upper( curr_plane + 1);
  2089. X
  2090. X        } else    /* mode 3 is only one allowed for output */
  2091. X        {
  2092. X            /*
  2093. X            **  We must output more info.
  2094. X            */
  2095. X
  2096. X            Process( bytes, 'V' );    /* convert to plane */
  2097. X
  2098. X            curr_plane++;
  2099. X
  2100. X            while ( curr_plane < num_planes )
  2101. X            {
  2102. X                /*
  2103. X                **  Restart graphics data sequence.
  2104. X                */
  2105. X
  2106. X                putchar ( ESC );
  2107. X                putchar ( '*' );
  2108. X                putchar ( 'b' );
  2109. X
  2110. X                /*
  2111. X                **  Call Process() with 0 bytes instead
  2112. X                **  of just doing output because we
  2113. X                **  need Process() to zero the appropriate
  2114. X                **  seed rows, and to use mode 3 to clear
  2115. X                **  the seed rows in the output (printer).
  2116. X                */
  2117. X
  2118. X                if ( curr_plane + 1 == num_planes )
  2119. X
  2120. X                    Process(0, 'W');    /* last plane */
  2121. X                else
  2122. X                    Process(0, 'V');
  2123. X
  2124. X                curr_plane++;
  2125. X            }
  2126. X        }
  2127. X    } else        /* inmode == 3 */
  2128. X    {
  2129. X        /*
  2130. X        **  Inmode is 3, so make outmode be 3 so we can do nothing.
  2131. X        */
  2132. X
  2133. X        if ( mode3 )            /* is mode 3 allowed? */
  2134. X        {
  2135. X            mode0 =
  2136. X            mode1 =
  2137. X            mode2 = FALSE;
  2138. X
  2139. X            Process(bytes, 'W');
  2140. X
  2141. X            mode0 = save0;        /* restore modes */
  2142. X            mode1 = save1;
  2143. X            mode2 = save2;
  2144. X
  2145. X        } else                /* ooops, no mode 3 */
  2146. X        {
  2147. X            /*
  2148. X            **  We must output more info.
  2149. X            */
  2150. X
  2151. X            Process( bytes, 'V' );    /* convert to plane */
  2152. X
  2153. X            curr_plane++;
  2154. X
  2155. X            while ( curr_plane < num_planes )
  2156. X            {
  2157. X                /*
  2158. X                **  Restart graphics data sequence.
  2159. X                */
  2160. X
  2161. X                putchar ( ESC );
  2162. X                putchar ( '*' );
  2163. X                putchar ( 'b' );
  2164. X
  2165. X                /*
  2166. X                **  Call Process() with 0 bytes instead
  2167. X                **  of just doing output because we
  2168. X                **  need Process() to use the seed rows
  2169. X                **  to create non-mode3 data.
  2170. X                */
  2171. X
  2172. X                if ( curr_plane + 1 == num_planes )
  2173. X
  2174. X                    Process(0, 'W');    /* last plane */
  2175. X                else
  2176. X                    Process(0, 'V');
  2177. X
  2178. X                curr_plane++;
  2179. X            }
  2180. X        }
  2181. X    }
  2182. }
  2183. X
  2184. X
  2185. /*
  2186. **  Process_extra() is to handle the extra planes.  That is, for PaintJets,
  2187. **  when sending 3 planes of data using <esc>*b#V, many drivers send a
  2188. **  fourth plane as <esc>*b0W to terminate the row, instead of the recommended
  2189. **  'W' as the 3rd plane.  This routine handles the extra without disturbing
  2190. **  the mode 3 seed rows.
  2191. **
  2192. **  In the future, this routine could be used to strip out the 4th plane.
  2193. */
  2194. X
  2195. Process_extra(bytes, terminator)
  2196. int    bytes;
  2197. char    terminator;
  2198. {
  2199. X    int  i;
  2200. X
  2201. X    /* toss any excess data */
  2202. X
  2203. X    for(i = 0; i < bytes; i++)
  2204. X       getchar();
  2205. X
  2206. X    /* last plane? force move down to next row */
  2207. X
  2208. X    if(terminator == 'W')
  2209. X    {
  2210. X        /* <esc>*b has already been output */
  2211. X        printf("0W");
  2212. X
  2213. X        firstrow = FALSE;        /* not on first row anymore */
  2214. X
  2215. X    }
  2216. X
  2217. }
  2218. X
  2219. /*
  2220. **  ChangeMode() simply outputs the sequence to change compression modes.
  2221. */
  2222. X
  2223. ChangeMode(newmode)
  2224. int newmode;
  2225. {
  2226. X    /*
  2227. X    **  <esc>*b have already been output.
  2228. X    **  terminator is 'm' instead of 'M' since will be followed by 'W'
  2229. X    */
  2230. X    printf("%1dm", newmode);
  2231. X    outmode = newmode;
  2232. }
  2233. X
  2234. X
  2235. /*-----------------------------------------------------------------------*\
  2236. X |                                                                       |
  2237. X |  Function Name: Mode_0_Graphics                                       |
  2238. X |                                                                       |
  2239. X |  Description:                                                         |
  2240. X |                                                                       |
  2241. X |  This is the routine that handles a Mode 0 graphics block transfer    |
  2242. X |  to the Formatter Module.                                             |
  2243. X |                                                                       |
  2244. \*-----------------------------------------------------------------------*/
  2245. X
  2246. /* FUNCTION */
  2247. X
  2248. Mode_0_Graphics(input_bytes, output_bytes, address)
  2249. X
  2250. unsigned int
  2251. X   input_bytes,                 /* Count of bytes to be read. */
  2252. X   output_bytes;                /* Count of bytes to be stored. */
  2253. X
  2254. unsigned char
  2255. X   *address;                    /* Pointer to where to store bytes. */
  2256. X
  2257. {
  2258. X   /* LOCAL VARIABLES */
  2259. X
  2260. X   unsigned char
  2261. X      *store_ptr;               /* Pointer to where to store the byte. */
  2262. X
  2263. X   unsigned int
  2264. X      read_bytes,               /* Local copy of input_bytes. */
  2265. X      write_bytes;              /* Local copy of output_bytes. */
  2266. X
  2267. X   /* CODE */
  2268. X
  2269. X   /* Initialize the local variables. */
  2270. X
  2271. X   read_bytes = input_bytes;
  2272. X   write_bytes = output_bytes;
  2273. X   store_ptr = address;
  2274. X   
  2275. X
  2276. X   /* transfer the lesser of available bytes or available room */
  2277. X
  2278. X     Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
  2279. X
  2280. X   /* now zero fill or throw excess data away */
  2281. X
  2282. X   if ( read_bytes > write_bytes )
  2283. X      Discard_Block(read_bytes - write_bytes);        /* throw excess */
  2284. X   else {
  2285. X      store_ptr += read_bytes;                /* adjust pointer */
  2286. X      write_bytes -= read_bytes;            /* zero fill count */
  2287. X
  2288. X      memset(store_ptr, 0, write_bytes);
  2289. X   }
  2290. X
  2291. X   return ( input_bytes );
  2292. }
  2293. X
  2294. X
  2295. /*-----------------------------------------------------------------------*\
  2296. X |                                                                       |
  2297. X |  Function Name: Mode_1_Graphics                                       |
  2298. X |                                                                       |
  2299. X |  Description:                                                         |
  2300. X |                                                                       |
  2301. X |  This is the routine that handles a Mode 1 graphics block transfer    |
  2302. X |  to the Formatter Module.  Mode 1 graphics is a compacted mode.       |
  2303. X |  The data in Mode 1 is in pairs.  The first byte is a replicate       |
  2304. X |  count and the second byte is the data.  The data byte is stored      |
  2305. X |  then replicated the replicate count.  Therefore a replicate count    |
  2306. X |  of 0 means the data byte is stored once.  The input byte count       |
  2307. X |  must be an even amount for the data to be in byte pairs.             |
  2308. X |                                                                       |
  2309. \*-----------------------------------------------------------------------*/
  2310. X
  2311. /* FUNCTION */
  2312. X
  2313. Mode_1_Graphics(input_bytes, output_bytes, address)
  2314. X
  2315. unsigned int
  2316. X   input_bytes,                 /* Count of bytes to be read. */
  2317. X   output_bytes;                /* Count of bytes to be stored. */
  2318. X
  2319. unsigned char
  2320. X   *address;                    /* Pointer to where to store bytes. */
  2321. X
  2322. {
  2323. X   /* LOCAL VARIABLES */
  2324. X
  2325. X   unsigned char
  2326. X      *store_ptr,               /* Pointer to where to store the byte. */
  2327. SHAR_EOF
  2328. true || echo 'restore of pclcomp.c failed'
  2329. fi
  2330. echo 'End of  part 1'
  2331. echo 'File pclcomp.c is continued in part 2'
  2332. echo 2 > _shar_seq_.tmp
  2333. exit 0
  2334. exit 0 # Just in case...
  2335. -- 
  2336. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2337. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2338. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2339. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2340.